#include "stdafx.h"
#include "MetaXmlHandler.h"
#include <sstream>
#include <assert.h>
#include <comdef.h>
#include <list>
#include "Action.h"

MetaXmlHandler::MetaXmlHandler(const char* xml)
: m_bXmlValid(false)
{
  assert(NULL != xml);

  CoInitialize(NULL);

  hr = m_spXMLDOMDoc.CoCreateInstance(__uuidof(DOMDocument));
  if (FAILED(hr)) { 
    ::MessageBox(NULL, "Unable to create XML parser object", "Message Queue Error", MB_OK); 
  }
  if ( m_spXMLDOMDoc.p == NULL ) { 
    ::MessageBox(NULL, "Unable to create XML parser object", "Message Queue Error", MB_OK); 
  }

  hr = m_spXMLDOMDoc->loadXML(_bstr_t(xml), &bSuccess);
  if (S_OK != hr) m_bXmlValid = false;
  else m_bXmlValid = true;
}

MetaXmlHandler::~MetaXmlHandler()
{
  m_spXMLDOMDoc.Release();
}

bool MetaXmlHandler::testXml()
{
  return m_bXmlValid;
}

const char* MetaXmlHandler::testXmlEx(const char* expr)
{
  char* pszStr = NULL;
  long lCount = 0;
  CComPtr<IXMLDOMNode> pXMLDOMNode = NULL;
  CComPtr<IXMLDOMNodeList> pXMLDOMNodeList = NULL;
  if (m_bXmlValid) {
    if (S_OK == hr) hr = m_spXMLDOMDoc->selectNodes(_bstr_t(expr), &pXMLDOMNodeList);
    if (S_OK == hr) hr = pXMLDOMNodeList->get_length(&lCount);
    if (0 == lCount) OutputDebugString("* No elements selected when processing testXmlEx\n");
    if (S_OK == hr) hr = pXMLDOMNodeList->get_item(0, &pXMLDOMNode);
    if (S_OK == hr) hr = pXMLDOMNode->get_xml(&str);
    if (S_OK == hr) {
      pszStr = new char[_bstr_t(str).length()+1];
      memset(pszStr, 0, _bstr_t(str).length()+1);
      strncpy(pszStr, _bstr_t(str), _bstr_t(str).length());
    }
  }
  return pszStr;
}

const char* MetaXmlHandler::toXml()
{
  char* pszStr = NULL;
  if (!m_bXmlValid) return NULL;
  hr = m_spXMLDOMDoc->get_xml(&str);
  if (S_OK == hr) {
    pszStr = new char[_bstr_t(str).length()+1];
    memset(pszStr, 0, _bstr_t(str).length()+1);
    strncpy(pszStr, _bstr_t(str), _bstr_t(str).length());
    return pszStr;
  } else {
    return NULL;
  }
}

const char* MetaXmlHandler::getNodeValue(const char* pszExpr)
{
  char* pszStr = NULL;
  if (!m_bXmlValid) return NULL;
  CComPtr<IXMLDOMNode> pDomDoc = NULL;
  hr = m_spXMLDOMDoc->selectSingleNode(_bstr_t(pszExpr), &pDomDoc);
  if (S_OK == hr) hr = pDomDoc->get_text(&str);
  if (S_OK == hr) {
    pszStr = new char[_bstr_t(str).length()+1];
    memset(pszStr, 0, _bstr_t(str).length()+1);
    strncpy(pszStr, _bstr_t(str), _bstr_t(str).length());
    return pszStr;
  } else {
    return NULL;
  }
}

const char* MetaXmlHandler::getAttrValue(const char* pszExpr, const char* pszAttrName)
{
  char* pszStr = NULL;
  if (!m_bXmlValid) return NULL;
  CComPtr<IXMLDOMNode> pDomDoc = NULL, pNamedDoc = NULL;
  CComPtr<IXMLDOMNamedNodeMap> pDomMap = NULL;
  hr = m_spXMLDOMDoc->selectSingleNode(_bstr_t(pszExpr), &pDomDoc);
  if (S_OK == hr) hr = pDomDoc->get_attributes(&pDomMap);
  if (S_OK == hr) hr = pDomMap->getNamedItem(_bstr_t(pszAttrName), &pNamedDoc);
  if (S_OK == hr) hr = pNamedDoc->get_text(&str);
  if (S_OK == hr) {
    pszStr = new char[_bstr_t(str).length()+1];
    memset(pszStr, 0, _bstr_t(str).length()+1);
    strncpy(pszStr, _bstr_t(str), _bstr_t(str).length());
    return pszStr;
  } else {
    return NULL;
  }
}

std::list<std::string>& MetaXmlHandler::getNodeValues(const char* pszExpr, std::list<std::string>& liNodeNames)
{
  if (!m_bXmlValid) return liNodeNames;
  long l = 0;
  CComPtr<IXMLDOMNodeList> pDomDocLi = NULL;  
  hr = m_spXMLDOMDoc->selectNodes(_bstr_t(pszExpr), &pDomDocLi);
  if (S_OK == hr) hr = pDomDocLi->get_length(&l);
  for (int i=0; i<l; ++i) {
    {
      CComPtr<IXMLDOMNode> pDomNode = NULL;
      hr = pDomDocLi->get_item(i, &pDomNode);
      if (S_OK == hr) hr = pDomNode->get_text(&str);
      if (S_OK == hr) {
        std::string * s = new std::string(_bstr_t(str));      
        liNodeNames.push_back(*s);
      }
    }
  }
  return liNodeNames;
}

void MetaXmlHandler::getActionSteps(std::list<Step*>& list)
{
  HRESULT hr;
  BSTR value;
  CComPtr<IXMLDOMNode> pXMLDOMNode = NULL, pXMLDOMNode2 = NULL, pXMLDOMNode3 = NULL, 
                       pXMLDOMNode4 = NULL, pXMLDOMNodeStep = NULL, 
                       pXMLDOMNodeTraces = NULL, pXMLDOMNodeOuter = NULL;
  CComPtr<IXMLDOMNodeList> pXMLDOMNodeList = NULL;
  CComPtr<IXMLDOMNamedNodeMap> pXMLAttrs = NULL;
  long lStepCount = 0;

  list.clear();

  hr = m_spXMLDOMDoc->selectNodes(_bstr_t("//procedure/step"), &pXMLDOMNodeList);
  if (S_OK == hr) hr = pXMLDOMNodeList->get_length(&lStepCount);
  if (S_OK == hr) {
    //std::stringstream ss;
    //ss << "Proceduure, lStepCount["<< lStepCount <<"]";
    //ss << std::endl;
    //OutputDebugString(ss.str().c_str());

    for (int i=0; i<lStepCount; ++i) {
      _bstr_t seq, desc, cmd;

      if (S_OK == hr) hr = pXMLDOMNodeList->get_item(i, &pXMLDOMNode2);

      if (S_OK == hr) hr = pXMLDOMNode2->get_attributes(&pXMLAttrs);
      if (S_OK == hr) hr = pXMLAttrs->getNamedItem(_bstr_t("sequence"), &pXMLDOMNodeOuter);
      if (S_OK == hr) hr = pXMLDOMNodeOuter->get_text(&value);
      if (S_OK == hr) seq = _bstr_t(value);
      pXMLDOMNodeOuter = NULL;
      pXMLAttrs = NULL;

      if (S_OK == hr) hr = pXMLDOMNode2->selectSingleNode(_bstr_t("description"), &pXMLDOMNodeStep);
      if (S_OK == hr) hr = pXMLDOMNodeStep->get_text(&value);
      if (S_OK == hr) desc = _bstr_t(value);
      pXMLDOMNodeStep = NULL;

      if (S_OK == hr) hr = pXMLDOMNode2->selectSingleNode(_bstr_t("command"), &pXMLDOMNodeStep);
      if (S_OK == hr) hr = pXMLDOMNodeStep->get_text(&value);
      if (S_OK == hr) cmd = _bstr_t(value);
      pXMLDOMNodeStep = NULL;

      pXMLDOMNode2 = NULL;

      Step * aStep = new Step(atol(seq), desc, cmd);
      list.push_back(aStep);
    }
  }
}

long MetaXmlHandler::getNodeCount(const char* pszExpr)
{
  long lCount = 0;
  CComPtr<IXMLDOMNodeList> pXMLDOMNodeList = NULL, pXMLDOMNodeList2 = NULL;  
  hr = m_spXMLDOMDoc->selectNodes(_bstr_t(pszExpr), &pXMLDOMNodeList);
  if (S_OK == hr) hr = pXMLDOMNodeList->get_length(&lCount);
  return lCount;
}

void MetaXmlHandler::getActionTraces(std::list<Trace*>& list)
{
  HRESULT hr;
  BSTR value;
  CComPtr<IXMLDOMNode> pXMLDOMNode = NULL, pXMLDOMNode2 = NULL, pXMLDOMNode3 = NULL, 
                       pXMLDOMNode4 = NULL, pXMLDOMNodeStep = NULL, 
                       pXMLDOMNodeTraces = NULL, pXMLDOMNodeOuter = NULL;
  CComPtr<IXMLDOMNodeList> pXMLDOMNodeList = NULL;
  CComPtr<IXMLDOMNamedNodeMap> pXMLAttrs = NULL;
  long lCount = 0;

  list.clear();

  hr = m_spXMLDOMDoc->selectNodes(_bstr_t("//trace"), &pXMLDOMNodeList);
  if (S_OK == hr) hr = pXMLDOMNodeList->get_length(&lCount);
  if (S_OK == hr) {
    for (int i=0; i<lCount; ++i) {
      _bstr_t classname, method, direction;

      if (S_OK == hr) hr = pXMLDOMNodeList->get_item(i, &pXMLDOMNode2);
      
      if (S_OK == hr) hr = pXMLDOMNode2->selectSingleNode(_bstr_t("object/class"), &pXMLDOMNodeOuter);      
      if (S_OK == hr) hr = pXMLDOMNodeOuter->get_text(&value);
      if (S_OK == hr) classname = _bstr_t(value);
      pXMLDOMNodeOuter = NULL;
        
      if (S_OK == hr) hr = pXMLDOMNode2->selectSingleNode(_bstr_t("object/method"), &pXMLDOMNodeOuter);      
      if (S_OK == hr) hr = pXMLDOMNodeOuter->get_text(&value);
      if (S_OK == hr) method = _bstr_t(value);

      if (S_OK == hr) hr = pXMLDOMNodeOuter->get_attributes(&pXMLAttrs);
      if (S_OK == hr) hr = pXMLAttrs->getNamedItem(_bstr_t("event"), &pXMLDOMNode3);
      if (S_OK == hr) hr = pXMLDOMNode3->get_text(&value);
      if (S_OK == hr) direction = _bstr_t(value);

      pXMLDOMNodeOuter = NULL;
      pXMLDOMNode3 = NULL;
      pXMLAttrs = NULL;

      pXMLDOMNode2 = NULL;

      Trace * t = new Trace(classname, method, direction);
      list.push_back(t);
    }
  }
}

const char* MetaXmlHandler::toXml(const char* expr)
{
  CComPtr<IXMLDOMNode> pXmlNode = NULL;
  char* pszStr = NULL;
  if (!m_bXmlValid) return NULL;
  hr = m_spXMLDOMDoc->selectSingleNode(_bstr_t(expr), &pXmlNode);
  if (S_OK == hr) hr = pXmlNode->get_xml(&str);
  if (S_OK == hr) {
    pszStr = new char[_bstr_t(str).length()+1];
    memset(pszStr, 0, _bstr_t(str).length()+1);
    strncpy(pszStr, _bstr_t(str), _bstr_t(str).length());
    return pszStr;
  } else {
    return NULL;
  }
}